package com.dawnling.androidutils.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.blankj.utilcode.util.ToastUtils;

/**
 * Des: 图片裁剪上层视图
 * Created by dawnLing on 2020/4/26
 */
public class ChooseArea extends View {

    private Context _context;
    private Paint paintDrawCircle;
    private Paint paintDrawInnerCircle;
    private Paint paintDrawLine;
    private boolean shouldIntercept;

    public ChooseArea(Context context) {
        super(context);
        _context = context;
        init();
    }

    public ChooseArea(Context context, AttributeSet attrs) {
        super(context, attrs);
        _context = context;
        init();
    }

    public ChooseArea(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        _context = context;
        init();
    }

    private void init() {
        // 四个角的外圆圆圈的画笔
        paintDrawCircle = new Paint();
        paintDrawCircle.setStyle(Paint.Style.STROKE);
        paintDrawCircle.setStrokeWidth(SizeUtils.dp2px(1));
        paintDrawCircle.setColor(Color.argb(255, 91, 180, 59));
        paintDrawCircle.setAntiAlias(true);

        // 四个角的内圆圈的画笔
        paintDrawInnerCircle = new Paint();
        paintDrawInnerCircle.setStyle(Paint.Style.FILL);
        paintDrawInnerCircle.setStrokeWidth(SizeUtils.dp2px(1));
        paintDrawInnerCircle.setColor(Color.argb(141, 255, 255, 255));
        paintDrawInnerCircle.setAntiAlias(true);


        // 全透明区边框的画笔
        paintDrawLine = new Paint();
        paintDrawLine.setStyle(Paint.Style.STROKE);
        paintDrawLine.setStrokeWidth(SizeUtils.dp2px(1));
        paintDrawLine.setColor(Color.argb(255, 91, 180, 59));
        paintDrawLine.setAntiAlias(true);
    }

    // 这4个点就是代表着4个控制点，顺序是这样的：
    /**
     * 0*********1
     * *         *
     * 5        4
     * *         *
     * 3*********2
     */
    private Point[] p = null;
    private IPointChangeListener pointChangeListener;

    public void setPointChangeListener(IPointChangeListener listener) {
        this.pointChangeListener = listener;
    }

    private void onPointChanged() {
        if (pointChangeListener != null) {
            pointChangeListener.change(p);
        }
    }

    public void setRegion(Point p0, Point p1, Point p2, Point p3) {
        p = new Point[6];
        p[0] = new Point(p0);
        p[1] = new Point(p1);
        p[2] = new Point(p2);
        p[3] = new Point(p3);
        p[4] = getLineCenterPoint(p1, p2);
        p[5] = getLineCenterPoint(p3, p0);
    }


    //获取直线的中间点
    private Point getLineCenterPoint(Point p1, Point p2) {
        return new Point((p2.x + p1.x) / 2, (p2.y + p1.y) / 2);
    }

    private int currentPoint = -1;

    private View bottomView = null;

    public void setBottomView(View bottomView) {
        this.bottomView = bottomView;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // 对于超出边界的动作进行纠正， 这里的width和height在onDraw中已经初始化
        checkAndCorrect(event, width, height);

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                LogUtils.i("ACTION_DOWN");
                int index = findTheCoveredPoint(event.getX(), event.getY());
                if (index == -1) {
                    shouldIntercept = false;
                    return false;
                }
                shouldIntercept = true;
                currentPoint = index;
                break;
            case MotionEvent.ACTION_MOVE:
                if (currentPoint == -1)
                    return false;
                switch (currentPoint) {
                    case 0:
                    case 3:
                        resetXY(event);
                        p[5] = getLineCenterPoint(p[3], p[0]);
                        break;
                    case 1:
                    case 2:
                        resetXY(event);
                        p[4] = getLineCenterPoint(p[1], p[2]);
                        break;
                    case 4:
                        p[1].x = checkAndCorrectX(p[1].x + ((int) event.getX() - p[4].x));
                        p[2].x = checkAndCorrectX(p[2].x + ((int) event.getX() - p[4].x));
                        p[currentPoint].x = (int) event.getX();
                        break;
                    case 5:
                        p[0].x = checkAndCorrectX(p[0].x + ((int) event.getX() - p[5].x));
                        p[3].x = checkAndCorrectX(p[3].x + ((int) event.getX() - p[5].x));
                        p[currentPoint].x = (int) event.getX();
                        break;
                    default:
                        break;

                }
                LogUtils.i("move x=" + event.getX() + "y=" + event.getY());
//                onPointChanged();
                break;
            case MotionEvent.ACTION_UP:
                correctPoints();
                currentPoint = -1;
                onPointChanged();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                currentPoint = -1;
                return false;
            default:
                return false;
        }

        LogUtils.i("move x=" + event.getX() + "y=" + event.getY());
        // 把touch动作投递到底部的bottomView去，用于控制ZoomArea区域的同步移动
//        bottomView.perform(event);

        invalidate();

        return true;
    }

    private void checkAndCorrect(MotionEvent event, int width, int height) {
        float x = event.getX(), y = event.getY();
        if (x < 0)
            x = 0;
        else if (x > width)
            x = width;

        if (y < 0)
            y = 0;
        else if (y > height)
            y = height;
        event.setLocation(x, y);
    }

    private int checkAndCorrectX(int x) {
        int result = x;
        if (x < 0) result = 0;
        else if (x > width) result = width;
        return result;
    }

    private int checkAndCorrectY(int y) {
        int result = y;
        if (y < 0) result = 0;
        else if (y > height) result = height;
        return result;
    }

    //重新设置圆点的位置
    private void resetXY(MotionEvent event) {
        p[currentPoint].x = (int) event.getX();
        p[currentPoint].y = (int) event.getY();
    }

    private void correctPoints() {
        // 把各个点纠正到正常的位置
        if (p[0].x > p[1].x) exchange(0, 1);
        if (p[0].y > p[3].y) exchange(0, 3);
        if (p[3].x > p[2].x) exchange(3, 2);
        if (p[1].y > p[2].y) exchange(1, 2);

        // 计算每个角，角度过大的不能纠偏
        boolean flag = true;
        double edge1 = calculateEdge(p[0], p[1]);
        double edge2 = calculateEdge(p[2], p[1]);
        double edge3 = calculateEdge(p[3], p[2]);
        double edge4 = calculateEdge(p[3], p[0]);
        double diagonal1 = calculateEdge(p[2], p[0]);
        double diagonal2 = calculateEdge(p[3], p[1]);
        flag &= calculateAngle(edge1, edge4, diagonal2);
        flag &= calculateAngle(edge1, edge2, diagonal1);
        flag &= calculateAngle(edge2, edge3, diagonal2);
        flag &= calculateAngle(edge3, edge4, diagonal1);
        if (!flag) {
            ToastUtils.showShort("无法裁剪");
            // TODO : 当然这里还可以对全透明区的边框进行变色
        }
    }

    private double calculateEdge(Point p1, Point p2) {
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
    }

    /**
     * 使用余弦定理
     * cos(x) = (a^2+b^2-c^2) / 2*a*b
     * 其中p1对应的角度就是x
     *
     * @return
     */
    private boolean calculateAngle(double a, double b, double c) {
        double cosX = (a * a + b * b - c * c) / (2 * a * b);
        if (Math.abs(cosX) > 0.707)
            return false;
        return true;
    }

    private void exchange(int p1, int p2) {
        Point temp = new Point(p[p1]);
        p[p1] = new Point(p[p2]);
        p[p2] = new Point(temp);
    }


    // 与控制点相邻80个像素点就选中，因为我的手机是1080p的分辨率，如果分辨率不同这里最好设置成不同的数值
    private static final int BOUND = 80;

    // 计算出当前手指触控的是哪个控制点
    private int findTheCoveredPoint(float x, float y) {
        if (p == null)
            return -1;
        for (int i = 0; i < p.length; i++) {
            if (Math.sqrt((p[i].x - x) * (p[i].x - x) + (p[i].y - y) * (p[i].y - y)) - BOUND <= 0) {
                return i;
            }
        }
        return -1;
    }

    private int width, height;
    private boolean getParams = false;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (!getParams) {
            if (bottomView == null)
                throw new IllegalStateException("you must set the bottom view !");
            width = bottomView.getWidth();
            height = bottomView.getHeight();
            getParams = true;
        }

        // 画出中间全透明区域的边框
        Path path = getPath(p[0], p[1], p[4], p[2], p[3], p[5]);
        canvas.drawPath(path, paintDrawLine);

        // 画出四个角的小圈
        for (int i = 0; i < p.length; i++) {
            canvas.drawCircle(p[i].x, p[i].y, SizeUtils.dp2px(12), paintDrawInnerCircle);
            canvas.drawCircle(p[i].x, p[i].y, SizeUtils.dp2px(13), paintDrawCircle);
        }
    }

    private Path getPath(Point... points) {
        Path path = new Path();
        path.moveTo(points[0].x, points[0].y);
        for (int i = 1; i < points.length; i++) {
            path.lineTo(points[i].x, points[i].y);
        }
        path.close();

        return path;
    }

    public interface IPointChangeListener {
        void change(Point[] points);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (shouldIntercept) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        return super.dispatchTouchEvent(ev);
    }
}
